package com.sky.mapper.handler;

import com.sky.common.BaseEnum;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedTypes;
import org.apache.ibatis.type.TypeHandler;

import java.sql.*;

/**
 * mybatis自定义handler，用于对枚举值的映射
 * @param <E>
 */
@MappedTypes({BaseEnum.class})
public class GenericEnumTypeHandler<E extends Enum<E> & BaseEnum> implements TypeHandler<E> {

    private final Class<E> enumType;

    public GenericEnumTypeHandler(Class<E> enumType) {
        this.enumType = enumType;
    }

    @Override
    public void setParameter(PreparedStatement preparedStatement, int i, E e, JdbcType jdbcType) throws SQLException {
        if (preparedStatement == null) {
            preparedStatement.setNull(i, Types.INTEGER);
        } else {
            preparedStatement.setObject(i, e.getCode());
        }
    }

    @Override
    public E getResult(ResultSet resultSet, String s) throws SQLException {
        Object object = resultSet.getObject(s);
        try {
            return object == null ? null : parseEnum(object);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public E getResult(ResultSet resultSet, int i) throws SQLException {
        Object object = resultSet.getObject(i);
        try {
            return object == null ? null : parseEnum(object);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public E getResult(CallableStatement callableStatement, int i) throws SQLException {
        Object object = callableStatement.getObject(i);
        try {
            return object == null ? null : parseEnum(object);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    private E parseEnum(Object code) throws IllegalAccessException {
        for (E enumConstant :
                enumType.getEnumConstants()) {
            if (enumConstant.getCode().equals(code)) {
                return enumConstant;
            }
        }

        throw new IllegalAccessException("No enum constant for code: " + code);
    }
}
